@* Generator: Template TypeVisibility: Internal *@
@using System.Globalization
@using System.IO
@using System.Web
@using Elmah
@using MoreLinq
@inherits WebTemplateBase
@{
    const int defaultPageSize = 15;
    const int maximumPageSize = 100;

    var basePageName = Request.ServerVariables["URL"];
    
    //
    // Get the page index and size parameters within their bounds.
    //

    var pageSize = Convert.ToInt32(Request.QueryString["size"], CultureInfo.InvariantCulture);
    pageSize = Math.Min(maximumPageSize, Math.Max(0, pageSize));

    if (pageSize == 0)
    {
        pageSize = defaultPageSize;
    }

    var pageIndex = Convert.ToInt32(Request.QueryString["page"], CultureInfo.InvariantCulture);
    pageIndex = Math.Max(1, pageIndex) - 1;

    //
    // Read the error records.
    //

    var log = this.ErrorLog ?? ErrorLog.GetDefault(Context);
    var errorEntryList = new List<ErrorLogEntry>(pageSize);
    var totalCount = log.GetErrors(pageIndex, pageSize, errorEntryList);

    //
    // Set the title of the page.
    //

    var hostName = Environment.MachineName;
    var title = string.Format(@"Error log for {0} on {1} (Page #{2})",
                              log.ApplicationName, hostName, 
                              (pageIndex + 1).ToString("N0"));

    Layout = new Elmah.MasterPage
    {
        Context  = Context, /* TODO Consider not requiring this */
        Title    = title,
        Footnote = string.Format("This log is provided by the {0}.", log.Name),
        SpeedBarItems = new[] 
        {
            SpeedBar.RssFeed.Format(basePageName),
            SpeedBar.RssDigestFeed.Format(basePageName),
            SpeedBar.DownloadLog.Format(basePageName),
            SpeedBar.Help,
            SpeedBar.About.Format(basePageName),
        },
    };
    
    // If the application name matches the APPL_MD_PATH then its
    // of the form /LM/W3SVC/.../<name>. In this case, use only the 
    // <name> part to reduce the noise. The full application name is 
    // still made available through a tooltip.

    var simpleName = log.ApplicationName;

    if (string.Compare(simpleName, Request.ServerVariables["APPL_MD_PATH"],
        true, CultureInfo.InvariantCulture) == 0)
    {
        var lastSlashIndex = simpleName.LastIndexOf('/');

        if (lastSlashIndex > 0)
        {
            simpleName = simpleName.Substring(lastSlashIndex + 1);
        }
    }
}        
        <h1 id="PageTitle">
            Error Log for <span id="ApplicationName" title="@log.ApplicationName">@simpleName on @hostName</span>
        </h1>
        
        @if (errorEntryList.Count > 0)
        {
            // Write error number range displayed on this page and the
            // total available in the log, followed by stock
            // page sizes.

            var firstErrorNumber = pageIndex * pageSize + 1;
            var lastErrorNumber = firstErrorNumber + errorEntryList.Count - 1;
            var totalPages = (int)Math.Ceiling((double)totalCount / pageSize);

            // Write out a set of stock page size choices. Note that
            // selecting a stock page size re-starts the log 
            // display from the first page to get the right paging.

            var stockSizes =
                from sizes in new[]
                {
                    new[] { 10, 15, 20, 25, 30, 50, 100, },
                }
                from size in sizes.Index()
                let separator = 
                    size.Key + 1 == sizes.Length 
                    ? null 
                    : size.Key + 2 == sizes.Length 
                    ? " or " 
                    : ", "
                select LinkHere(basePageName, HtmlLinkType.Start, size.Value.ToString("N0"), 0, size.Value)
                     + separator;
            
            <p>Errors @firstErrorNumber.ToString("N0") to @lastErrorNumber.ToString("N0") 
                of total @totalCount.ToString("N0") 
                (page @((pageIndex + 1).ToString("N0")) of @totalPages.ToString("N0")). 
                Start with @Html(stockSizes.ToDelimitedString(string.Empty)) errors per page.</p>

            // Write out the main table to display the errors.

            <table id="ErrorLog" cellspacing="0" style="border-collapse:collapse;" class="table table-condensed table-striped">
                <tr>
                    <th class="host-col" style="white-space:nowrap;">Host</th>
                    <th class="code-col" style="white-space:nowrap;">Code</th>
                    <th class="type-col" style="white-space:nowrap;">Type</th>
                    <th class="error-col" style="white-space:nowrap;">Error</th>
                    <th class="user-col" style="white-space:nowrap;">User</th>
                    <th class="time-col" style="white-space:nowrap;">When</th>
                </tr>

            @foreach (var error in from item in errorEntryList.Index()
                                   let e = item.Value.Error
                                   select new
                                   {
                                       Index = item.Key,
                                       item.Value.Id,
                                       e.HostName,                                                 
                                       e.StatusCode,
                                       StatusDescription = 
                                          e.StatusCode > 0
                                          ? HttpStatus.FromCode(e.StatusCode).Reason
                                          : null,
                                       e.Type,
                                       HumaneType = ErrorDisplay.HumaneExceptionErrorType(e),
                                       e.Message,
                                       e.User,
                                       When = FuzzyTime.FormatInEnglish(e.Time),
                                       Iso8601Time = e.Time.ToString("o"),
                                   })
            {
                <tr class="@(error.Index % 2 == 0 ? "even" : "odd")">
                    
                    <td class="host-col" style="white-space:nowrap;">@error.HostName</td>
                    <td class="code-col" style="white-space:nowrap;">
                        @if (!string.IsNullOrEmpty(error.StatusDescription))
                        {
                            <span title="@error.StatusDescription">@error.StatusCode</span>
                        }
                        else if (error.StatusCode != 0)
                        {
                            @error.StatusCode
                        }
                    </td>
                    <td class="type-col" style="white-space:nowrap;"><span title="@error.Type">@error.HumaneType</span></td>
                    
                    <td class="error-col"><span>@error.Message</span> 
                        <a href="@basePageName/detail?id=@error.Id">Details&hellip;</a></td>
                    
                    <td class="user-col" style="white-space:nowrap;">@error.User</td>
                    <td class="time-col" style="white-space:nowrap;"><abbr title="@error.Iso8601Time">@error.When</abbr></td>
                </tr>
            }
            </table>

            // Write out page navigation links.

            //
            // If not on the last page then render a link to the next page.
            //

            var nextPageIndex = pageIndex + 1;
            var moreErrors = nextPageIndex * pageSize < totalCount;
            
            <p>

                @if (moreErrors)
                {
                    @LinkHere(basePageName, HtmlLinkType.Next, "Next errors", nextPageIndex, pageSize)
                }
                @if (pageIndex > 0 && totalCount > 0)
                {
                    if (moreErrors) {
                        Write("; ");
                    }
                    @LinkHere(basePageName, HtmlLinkType.Start, "Back to first page", 0, pageSize)
                }

            </p>
        }
        else
        {
            // No errors found in the log, so display a corresponding
            // message.

            // It is possible that there are no error at the requested 
            // page in the log (especially if it is not the first page).
            // However, if there are error in the log

            if (pageIndex > 0 && totalCount > 0)
            {
                <p>@LinkHere(basePageName, HtmlLinkType.Start, "Go to first page", 0, pageSize).</p>
            }
            else
            {
                <p>No errors found.</p>
            }
        }

@functions
{
    IHtmlString LinkHere(string basePageName, string type, string text, int pageIndex, int pageSize)
    {
        return new HtmlString(
            "<a"
            + new HtmlString(!string.IsNullOrEmpty(type) ? " rel=\"" + type + "\"" : null)
            + " href=\""
            + Encode(
                string.Format(CultureInfo.InvariantCulture, 
                    @"{0}?page={1}&size={2}",
                    basePageName,
                    pageIndex + 1,
                    pageSize))
            + "\">"
            + Encode(text)
            + "</a>"
        );
    } 
}
